/*
 * 
* Copyright (C) 2004-2009  Autodesk, Inc.
* 
* This library is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser
* General Public License as published by the Free Software Foundation.
* 
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
* 
 */


#include "stdafx.h"
#include "MapInfoClassDefinition.h"
#include "MapInfoConnection.h"
#include "MapInfoSpatialContext.h"
#include "OgrFdoUtil.h"
#include "MapInfoProvider.h"
#include "MapInfoCSOverrideFile.h"

#include <FdoCommonStringUtil.h>
#include <FdoCommonSchemaUtil.h>
#include <FdoCommonMiscUtil.h>
#include <FdoCommonStringUtil.h>

MapInfoClassDefinition::MapInfoClassDefinition(void)
{
    throw FdoException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_UNSPECIFIED_ERROR)));
}

MapInfoClassDefinition::~MapInfoClassDefinition(void)
{
}

MapInfoClassDefinition::MapInfoClassDefinition(
    MapInfoConnection* conn,
    IMapInfoFile* layer,
    FdoClassDefinition* fdoClass):
    m_connection(conn),
    m_parent(NULL),
    m_fdoClassDefinition(fdoClass)
{
    VALIDATE_ARGUMENT(conn);
    VALIDATE_ARGUMENT(layer);
    VALIDATE_ARGUMENT(fdoClass);
    FDO_SAFE_ADDREF(m_connection.p);
    m_mapinfoLayer = layer;  //NOTE: weak reference
    FDO_SAFE_ADDREF(m_fdoClassDefinition.p);
}

MapInfoFeatureSchema* MapInfoClassDefinition::GetParent()
{
    return m_parent;
}

void MapInfoClassDefinition::SetParent(MapInfoFeatureSchema* schema)
{
    m_parent = schema;
}

IMapInfoFile* MapInfoClassDefinition::GetMapInfoFile()
{
    return m_mapinfoLayer;
}

bool MapInfoClassDefinition::GetBounds(double &dXMin, double &dYMin, double &dXMax, double &dYMax)
{
    VALIDATE_ARGUMENT(m_mapinfoLayer);
    return (m_mapinfoLayer->GetBounds(dXMin, dYMin, dXMax, dYMax) == 0);
}

bool MapInfoClassDefinition::GetExtents(double &dXMin, double &dYMin, double &dXMax, double &dYMax)
{
    VALIDATE_ARGUMENT(m_mapinfoLayer);
    OGREnvelope extent;
    bool ret = (m_mapinfoLayer->GetExtent(&extent, TRUE) == OGRERR_NONE);
    if (ret)
    {
        dXMin = extent.MinX;
        dYMin = extent.MinY;
        dXMax = extent.MaxX;
        dYMax = extent.MaxY;
    }
    return ret;
}

int MapInfoClassDefinition::GetFeatureCount()
{
    VALIDATE_ARGUMENT(m_mapinfoLayer);
    return m_mapinfoLayer->GetFeatureCount(TRUE);
}

FdoDataPropertyDefinitionCollection* MapInfoClassDefinition::GetIdentityProperty()
{
    VALIDATE_ARGUMENT(m_fdoClassDefinition.p);
    return m_fdoClassDefinition->GetIdentityProperties();
}

FdoStringP MapInfoClassDefinition::GetIdentityPropertyName()
{
    VALIDATE_ARGUMENT(m_fdoClassDefinition.p);
    FdoPtr<FdoDataPropertyDefinitionCollection> idProps = m_fdoClassDefinition->GetIdentityProperties();
    if (idProps->GetCount() > 0)
    {
        FdoPtr<FdoDataPropertyDefinition> idProp = idProps->GetItem(0);
        return idProp->GetName();
    }
    else
        return DEFAULT_FEATURE_ID_PROPERTY_NAME;
}

FdoStringP MapInfoClassDefinition::GetGeometryPropertyName()
{
    VALIDATE_ARGUMENT(m_fdoClassDefinition.p);
    FdoPtr<FdoPropertyDefinitionCollection> props = m_fdoClassDefinition->GetProperties();
    for (int i = 0; i < props->GetCount(); ++i)
    {
        FdoPtr<FdoPropertyDefinition> prop = props->GetItem(i);
        FdoGeometricPropertyDefinition* geomProp = dynamic_cast<FdoGeometricPropertyDefinition*>(prop.p);
        if (geomProp != NULL)
            return geomProp->GetName();
    }
    return DEFAULT_GEOMETRY_PROPERTY_NAME;
}

// Get logical class:
FdoClassDefinition* MapInfoClassDefinition::GetFdoClass(void)
{
    return FDO_SAFE_ADDREF(m_fdoClassDefinition.p);
}

bool MapInfoClassDefinition::HasData()
{
    return (m_mapinfoLayer->GetRealFeatureCount() > 0);
}

void MapInfoClassDefinition::DeleteMapInfoFile()
{
#pragma message("TODO: Check return value and throw an exception if there are some errors.")
    if (HasData())
        throw FdoCommandException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_CANNOT_MODIFY_SCHEMA)));

    OGRTABDataSource* datastore = m_connection->GetOGRDataSource();
    if (NULL == datastore)
        throw FdoException::Create(NlsMsgGetMain(FDO_NLSID(FDO_63_CONNECTION_INVALID)));
    
    int nIndex = datastore->GetLayerIndex(m_mapinfoLayer);
    if (nIndex < 0)
        throw FdoException::Create(FdoException::NLSGetMessage(FDO_NLSID(MAPINFOPROVIDER_DELETE_CLASS), m_fdoClassDefinition->GetName()));

    datastore->DeleteLayer(nIndex);
}

void MapInfoClassDefinition::ModifyMapInfoFile(FdoClassDefinition* fdoClass)
{
    VALIDATE_ARGUMENT(fdoClass);
    ValidateProperty(fdoClass);

    OGRTABDataSource* datastore = m_connection->GetOGRDataSource();
    if (NULL == datastore)
        throw FdoException::Create(NlsMsgGetMain(FDO_NLSID(FDO_63_CONNECTION_INVALID)));

    int nIndex = datastore->GetLayerIndex(m_mapinfoLayer);
    if (nIndex < 0)
        throw FdoException::Create(FdoException::NLSGetMessage(FDO_NLSID(MAPINFOPROVIDER_MODIFY_CLASS), fdoClass->GetName()));

    m_mapinfoLayer = CreateMapInfoFile(m_connection, fdoClass, nIndex);
    FdoPtr<FdoClassDefinition> newFdoClassDef = FdoCommonSchemaUtil::DeepCopyFdoClassDefinition(fdoClass, NULL);
    RemoveDeletedProperty(fdoClass, newFdoClassDef);
    AddMissedProperty(newFdoClassDef);
    m_fdoClassDefinition = newFdoClassDef;
    FDO_SAFE_ADDREF(m_fdoClassDefinition.p);
}

FdoString* MapInfoClassDefinition::GetName()
{
    return m_fdoClassDefinition == NULL ? L"" : m_fdoClassDefinition->GetName();
}

MapInfoClassDefinition* MapInfoClassDefinition::CreateMapInfoClassDefinition(
    MapInfoConnection* conn,
    FdoClassDefinition* fdoClass)
{
    VALIDATE_ARGUMENT(conn);
    VALIDATE_ARGUMENT(fdoClass);

    ValidateProperty(fdoClass);
    IMapInfoFile* mapinfoFile = CreateMapInfoFile(conn, fdoClass);

    FdoPtr<FdoClassDefinition> newFdoClassDef = FdoCommonSchemaUtil::DeepCopyFdoClassDefinition(fdoClass, NULL);
    AddMissedProperty(newFdoClassDef);
    FdoPtr<MapInfoClassDefinition> mapinfoClassDef = new MapInfoClassDefinition(conn, mapinfoFile, newFdoClassDef);
    return mapinfoClassDef.Detach();
}

void MapInfoClassDefinition::RemoveDeletedProperty(
    FdoClassDefinition* oldFdoClass, 
    FdoClassDefinition* newFdoClass)
{
    FdoPtr<FdoPropertyDefinitionCollection> oldProps = oldFdoClass->GetProperties();
    FdoPtr<FdoPropertyDefinitionCollection> newProps = newFdoClass->GetProperties();
    for (int i = 0; i < oldProps->GetCount(); ++i)
    {
        FdoPtr<FdoPropertyDefinition> oldProp = oldProps->GetItem(i);
        if (oldProp->GetElementState() == FdoSchemaElementState_Deleted)
        {
            FdoInt32 nIndex = newProps->IndexOf(oldProp->GetName());
            if (nIndex >= 0)
                newProps->RemoveAt(nIndex);
        }
    }
}

void MapInfoClassDefinition::ValidateProperty(
    FdoClassDefinition* fdoClass)
{
    // Validate that there is one geometry property only
    int nGeometricPropCount = 0;
    int nDataPropertyCount = 0;
    FdoPtr<FdoStringCollection> dataPropNames = FdoStringCollection::Create();
    FdoPtr<FdoPropertyDefinitionCollection> props = fdoClass->GetProperties();
    for (int i = 0; i < props->GetCount(); ++i)
    {
        FdoPtr<FdoPropertyDefinition> prop = props->GetItem(i);
        FdoPropertyType propType = prop->GetPropertyType();
        if (FdoPropertyType_GeometricProperty == propType)
        {
            FdoGeometricPropertyDefinition* geoProperty = dynamic_cast<FdoGeometricPropertyDefinition*>(prop.p);
            // Users may delete the old geometry property and add a new geometry property
            if (geoProperty->GetElementState() != FdoSchemaElementState_Deleted)
                nGeometricPropCount++;
        }
        else if (FdoPropertyType_DataProperty == propType)
        {
            FdoDataPropertyDefinition* dataProperty = dynamic_cast<FdoDataPropertyDefinition*>(prop.p);
            // Users may delete the old data property and add a new data property
            if (dataProperty->GetElementState() != FdoSchemaElementState_Deleted)
            {
                nDataPropertyCount++;
                dataPropNames->Add(dataProperty->GetName());
            }
        }
    }
    if (nGeometricPropCount > 1)
        throw FdoCommandException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_MULTIPLE_GEOMETRY_PROP_NOT_SUPPORTED)));

    // Validate that there is one non-identity data property at least
    bool bHasNonIdentityDataProp = false;
    FdoPtr<FdoDataPropertyDefinitionCollection> idProperties = fdoClass->GetIdentityProperties();
    for (int i = 0; i < nDataPropertyCount; ++i)
    {
        if (idProperties->IndexOf(dataPropNames->GetString(i)) < 0)
        {
            bHasNonIdentityDataProp = true;
            break;
        }
    }
    if (nDataPropertyCount <= 0 || !bHasNonIdentityDataProp)
        throw FdoCommandException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_PROPERTY_INCORRECT_COUNT)));

    // Validate that there is exactly one identity property of type int32:
    bool bHasFeatureIdProp = (props->IndexOf(DEFAULT_FEATURE_ID_PROPERTY_NAME) >= 0);
    FdoPtr<FdoDataPropertyDefinition> idProperty;
    FdoString* className = fdoClass->GetName ();
    FdoInt32 nIdPropCount = idProperties->GetCount();
    if (nIdPropCount <= 0)
    {
        if (bHasFeatureIdProp)
            throw FdoException::Create(NlsMsgGetMain(MAPINFOPROVIDER_PROPERTY_INCORRECT_NAME, "MapInfo doesn't support a non-identity property with name '%1$ls'.", DEFAULT_FEATURE_ID_PROPERTY_NAME));
    }
    else if (nIdPropCount > 1)
        throw FdoException::Create(NlsMsgGetMain(MAPINFOPROVIDER_TOO_MANY_IDENTITY_PROPERTIES, "FDO class '%1$ls' has more than one identity property; only one identity property is supported.", className));
    else
    {
        idProperty = idProperties->GetItem(0);
        FdoString* propName = idProperty->GetName();
        if (bHasFeatureIdProp && wcscmp(DEFAULT_FEATURE_ID_PROPERTY_NAME, propName) != 0)
            throw FdoException::Create(NlsMsgGetMain(MAPINFOPROVIDER_PROPERTY_INCORRECT_NAME, "MapInfo doesn't support a non-identity property with name '%1$ls'.", DEFAULT_FEATURE_ID_PROPERTY_NAME));

        if (idProperty->GetDataType() != FdoDataType_Int32)
            throw FdoException::Create(NlsMsgGetMain(MAPINFOPROVIDER_IDENTITY_PROPERTY_INCORRECT_TYPE, "FDO class '%1$ls' has an identity property of type '%2$ls'; only type 'Int32' is supported.",
                className, FdoCommonMiscUtil::FdoDataTypeToString(idProperty->GetDataType())));
    }
}

void MapInfoClassDefinition::AddMissedProperty(FdoClassDefinition* fdoClass)
{
    // Add identity property if necessary
    FdoPtr<FdoPropertyDefinitionCollection> props = fdoClass->GetProperties();
    FdoPtr<FdoDataPropertyDefinitionCollection> idProperties = fdoClass->GetIdentityProperties();
    if (idProperties->GetCount() <= 0)
    {
        FdoPtr<FdoDataPropertyDefinition> idProperty = FdoDataPropertyDefinition::Create (DEFAULT_FEATURE_ID_PROPERTY_NAME, L"");
        idProperty->SetDataType (FdoDataType_Int32);
        idProperty->SetIsAutoGenerated (true);
        idProperty->SetNullable (false);
        props->Insert(0, idProperty);
        idProperties->Add (idProperty);
    }

    // Add geometric property if necessary
    int nGeometricPropCount = 0;
    for (int i = 0; i < props->GetCount(); ++i)
    {
        FdoPtr<FdoPropertyDefinition> prop = props->GetItem(i);
        FdoPropertyType propType = prop->GetPropertyType();
        if (FdoPropertyType_GeometricProperty == propType)
        {
            FdoGeometricPropertyDefinition* geoProperty = dynamic_cast<FdoGeometricPropertyDefinition*>(prop.p);
            // Users may delete the old geometry property and add a new geometry property
            if (geoProperty->GetElementState() != FdoSchemaElementState_Deleted)
                nGeometricPropCount++;
        }
    }
    if (nGeometricPropCount <= 0)
    {
        // geometry property
        FdoPtr<FdoGeometricPropertyDefinition> geoProperty = FdoGeometricPropertyDefinition::Create(DEFAULT_GEOMETRY_PROPERTY_NAME, L"");;
        geoProperty->SetGeometryTypes((FdoGeometricType)(FdoGeometricType_Point | FdoGeometricType_Curve | FdoGeometricType_Surface));
        props->Add(geoProperty);
    }
}

IMapInfoFile* MapInfoClassDefinition::CreateMapInfoFile(
    MapInfoConnection* conn,
    FdoClassDefinition* fdoClass,
    int nIndex /* = -1*/)
{
    VALIDATE_ARGUMENT(conn);
    VALIDATE_ARGUMENT(fdoClass);

    // Get WKT format coordinate system
    FdoString* wkt = NULL;
    OGRSpatialReference* spatialReference = NULL;
    FdoPtr<MapInfoSpatialContext> spatialContext;
    FdoPtr<FdoPropertyDefinitionCollection> props = fdoClass->GetProperties();
    FdoPtr<MapInfoSpatialContextCollection> spatialContexts = conn->GetSpatialContexts();
    for (int i = 0; i < props->GetCount(); ++i)
    {
        FdoPtr<FdoPropertyDefinition> prop = props->GetItem(i);
        if (FdoPropertyType_GeometricProperty == prop->GetPropertyType())
        {
            FdoGeometricPropertyDefinition* geoProperty = dynamic_cast<FdoGeometricPropertyDefinition*>(prop.p);
            // Users may delete the old geometry property and add a new geometry property
            if (geoProperty->GetElementState() != FdoSchemaElementState_Deleted)
            {
                FdoString* spatialContextName = geoProperty->GetSpatialContextAssociation();
                // Actually if spatial context of a geometry doesn't exist, we should throw an exception.
                // However, it will result in bulkcopy doesn't work.
                if (spatialContextName != NULL && wcslen(spatialContextName) > 0 && spatialContexts->Contains(spatialContextName))
                {
                    spatialContext = spatialContexts->GetItem(spatialContextName);
                    wkt = spatialContext->GetCoordinateSystemWkt();
                    if (wkt != NULL && wcslen(wkt) > 0)
                    {
                        char* mbWKT = NULL;
                        wide_to_multibyte(mbWKT, wkt);                
                        spatialReference = new OGRSpatialReference(mbWKT);
                    }
                    break;
                }
            }
        }
    }
    
    OGRTABDataSource* datastore = conn->GetOGRDataSource();
    if (NULL == datastore)
        throw FdoException::Create(NlsMsgGetMain(FDO_NLSID(FDO_63_CONNECTION_INVALID)));

    FdoString* className = fdoClass->GetName();
    FdoPtr<FdoSchemaElement> schema = fdoClass->GetParent();
    if (schema.p == NULL)
        throw FdoCommandException::Create(NlsMsgGetMain(MAPINFOPROVIDER_ADD_CLASS, "Failed to add class '%1$ls'.", className));

    FdoStringP schemaName = schema->GetName();
    TABFileClass fileType = TABFC_TABFile;
    if (schemaName == TAB_SCHEMA_NAME)
        fileType = TABFC_TABFile;
    else if (schemaName == MIF_SCHEMA_NAME)
        fileType = TABFC_MIFFile;
    else if (schemaName == VIEW_SCHEMA_NAME)
        fileType = TABFC_TABView;
    else if (schemaName == SEAMLESS_SCHEMA_NAME)
        fileType = TABFC_TABSeamless;
    else
        throw FdoCommandException::Create(NlsMsgGetMain(MAPINFOPROVIDER_ADD_CLASS, "Failed to add class '%1$ls'.", className));

    W2A(className);
    IMapInfoFile *poFile = NULL;
    if (nIndex < 0)
        poFile = datastore->CreateMapInfoLayer(mbclassName, spatialReference, fileType);
    else
        poFile = datastore->UpdateMapInfoLayer(nIndex, mbclassName, spatialReference, fileType);

    if (spatialReference && spatialReference->Dereference() == 0)
        delete spatialReference;

    if (poFile == NULL)
        throw FdoCommandException::Create(NlsMsgGetMain(MAPINFOPROVIDER_ADD_CLASS, "Failed to add class '%1$ls'.", className));

    // Set bounds of MapInfo file
    if (spatialContext.p != NULL)
    {
        FdoPtr<FdoFgfGeometryFactory> factory = FdoFgfGeometryFactory::GetInstance();
        FdoPtr<FdoByteArray> extent = spatialContext->GetExtent();
        if (extent.p != NULL && factory.p != NULL)
        {
            FdoPtr<FdoIGeometry> geom_box = factory->CreateGeometryFromFgf(extent);
            if (geom_box.p != NULL)
            {
                FdoPtr<FdoIEnvelope> box = geom_box->GetEnvelope();
                if (box.p != NULL)
                    poFile->SetBounds(box->GetMinX(), box->GetMinY(), box->GetMaxX(), box->GetMaxY());
            }
        }
    }

    // Get identity property name. MapInfo can have one identity property only.
    FdoString* idPropName = NULL;
    bool bHasIdentityProp = false;
    FdoPtr<FdoDataPropertyDefinitionCollection> idProperties = fdoClass->GetIdentityProperties();
    if (idProperties->GetCount() > 0)
    {
        FdoPtr<FdoDataPropertyDefinition> idProperty = idProperties->GetItem(0);
        idPropName = idProperty->GetName ();
    }
    if (idPropName != NULL && wcslen(idPropName) > 0)
        bHasIdentityProp = true;

    props = fdoClass->GetProperties();
    for (int i = 0; i < props->GetCount(); ++i)
    {
        FdoPtr<FdoPropertyDefinition> prop = props->GetItem(i);
        FdoString* propName = prop->GetName();
        
        if (prop->GetElementState() == FdoSchemaElementState_Deleted)
            continue;

        // Ignore the identity property because MapInfo will create an identity
        // property automically by using row id.
        if (bHasIdentityProp && wcscmp(idPropName, propName) == 0)
            continue;

        FdoPropertyType propType = prop->GetPropertyType();
        switch (propType)
        {
        case FdoPropertyType_DataProperty:
            {
                FdoDataPropertyDefinition* dataProperty = dynamic_cast<FdoDataPropertyDefinition*>(prop.p);
                CreateDataProperty(poFile, dataProperty);
                break;
            }
        case FdoPropertyType_GeometricProperty:
            {
                FdoGeometricPropertyDefinition* geoProperty = dynamic_cast<FdoGeometricPropertyDefinition*>(prop.p);
                CreateGeometricProperty(poFile, geoProperty);
                break;
            }
        case FdoPropertyType_ObjectProperty:
            poFile->Destory();
            throw FdoCommandException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_OBJECT_PROPERTY)));
        case FdoPropertyType_RasterProperty:
            poFile->Destory();
            throw FdoCommandException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_NO_RASTERS)));
            break;
        case FdoPropertyType_AssociationProperty:
            poFile->Destory();
#pragma message("TODO: MapInfo supports association. We need to implement it later.")
            throw FdoCommandException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_ASSOCIATION_PROPERTY)));
            break;
        default:
            poFile->Destory();
            throw FdoCommandException::Create(NlsMsgGetMain(FDO_NLSID(MAPINFOPROVIDER_UNKNOWN_PROPERTY_TYPE)));
            break;
        }
    }
    poFile->Reopen(TABRead);
    
    // Create coordinate system override file
    const char* directory = datastore->GetName();
    const char* fullFilename;
    if (fileType == TABFC_TABFile)
        fullFilename = CPLFormFilename( directory, mbclassName, "prt" );
    else if (fileType == TABFC_MIFFile)
        fullFilename = CPLFormFilename( directory, mbclassName, "prm" );
    if (fullFilename != NULL)
    {
        A2W(fullFilename);
        MapInfoCSOverrideFile temp(wfullFilename, wkt);
    }

    return poFile;
}

void MapInfoClassDefinition::CreateDataProperty(
    IMapInfoFile* layer,
    FdoDataPropertyDefinition* propDef)
{
    VALIDATE_ARGUMENT(layer);
    VALIDATE_ARGUMENT(propDef);
    TABFieldType ft = OgrFdoUtil::FdoDataType2TABFieldType(propDef->GetDataType());
    FdoString* propName = propDef->GetName();

    char* mbPropName = NULL;
#ifdef _WIN32
    FdoStringP pLocale = FdoStringP(setlocale(LC_ALL, NULL));
    FdoStringP pCodePage = pLocale.Right(L".");
    wide_to_multibyte_cpg (mbPropName, propName, pCodePage.ToLong());
#else
    wide_to_multibyte (mbPropName, propName);
#endif

    if(ft == TABFDecimal)
        layer->AddDecimalNative(mbPropName, ft, propDef->GetPrecision(), propDef->GetScale());
    else
        layer->AddFieldNative(mbPropName, ft, propDef->GetLength(), propDef->GetPrecision());
}

void MapInfoClassDefinition::CreateGeometricProperty(
    IMapInfoFile* layer,
    FdoGeometricPropertyDefinition* propDef)
{
    // Geometry type is decided when the first geometry is inserted.
    // So we don't need to add it in MapInfo file.
}


int MapInfoClassDefinition::GetPropertyIndex(FdoString * strPropertyName)
{
    TABFile * pTabFile = dynamic_cast<TABFile *>(m_mapinfoLayer);
    if(!pTabFile)
        return 0;

    TABDATFile * pDATFile = pTabFile->GetDATFileRef();
    for(int i = 0; i < pDATFile->GetNumFields(); i++)
    {
        // Compare the field name and strPropertyName
        char * strPropName = NULL;
        
        wide_to_multibyte(strPropName, strPropertyName);
        if(strPropName)
        {
            if(!strcmp(strPropName, pDATFile->GetFieldName(i)))
                return pTabFile->GetFieldIndexNumber(i);
        }
    }
    return 0;
}

GByte * MapInfoClassDefinition::GenerateIndexKey(int index, FdoDataValue * val)
{
    TABFile * pTabFile = dynamic_cast<TABFile *>(m_mapinfoLayer);
    if(!pTabFile)
        return NULL;

    if(index <= 0)
        return NULL;

    OGRField* ogrValue = OgrFdoUtil::FdoDataValue2OGRField(val);

    TABDATFile * pDATFile = pTabFile->GetDATFileRef();
    TABFieldType fieldType = pDATFile->GetFieldType(index);
    switch(fieldType)
    {
    case TABFChar:
        return pTabFile->GetINDFileRef()->BuildKey(index, ogrValue->String);
    case TABFInteger:
    case TABFSmallInt:
    case TABFDate:
    case TABFTime:
    case TABFDateTime:
    case TABFLogical:
        return pTabFile->GetINDFileRef()->BuildKey(index, ogrValue->Integer);
    case TABFDecimal:
    case TABFFloat:
        return pTabFile->GetINDFileRef()->BuildKey(index, ogrValue->Real);
    }

    return NULL;
}


int MapInfoClassDefinition::GetKeyLength(int index)
{
    TABFile * pTabFile = dynamic_cast<TABFile *>(m_mapinfoLayer);
    if(!pTabFile)
        return 0;

    TABINDFile * pINDFile = pTabFile->GetINDFileRef();
    return pINDFile->GetKeyLength(index);
}
